const EventState={
    accepted:0,
    rejected:1,
    pending:2,
    interrupted:3
};

export class CombatEvent{
    constructor(type,launcher,payload,reason){
        this.reset(type,launcher,payload,reason);
    }

    reset(type,launcher,payload,reason){
        this.type=type;
        this.launcher=launcher;


        this.lastBase=null;//做出最终决定的对象
        this.onaccept=null;
        this.onreject=null;

        this.lastState=EventState.accepted;//用于保存中断前的状态
        this.state=EventState.accepted;

        this.payload=payload;

        this.reason=reason;

        //自己悬挂的事件
        this.parent=null;
        /**
         * @type {{base,event:CombatEvent}[]}
         */
        this.children=[];
    }

    /**
     * 比如
     * CombatEventBus.on(
     * 'a',(event)=>{
     *  let event=pool.new();
     *  CombatEventBus.dispatch(
     *      
     *  );
     *  event.setPending(this,event,);
     * }
     * )
     */

    interrupt(){
        if(this.state!=EventState.interrupted){
            this.lastState=this.state;
        }
        this.state=EventState.interrupted;
    }

    resume(){this.state=this.lastState;}

    reject(base){
        if(!this.lastBase||this.lastBase.isLowerEqualPriority(base)){
            if(this.isPending()){
                let index=this.children.findIndex(c=>c.base==base);
                if(index>=0){
                    this.children.splice(index,1);
                    if(this.children.length>0)
                        return;
                }else if(this.children[0].isEqualPriority(base)){
                    return;
                }
            }
            this._reject(base);
        }
    }

    _reject(base){
        this.state=EventState.rejected;
        this.lastBase=base;
    }

    accept(base){
        if(!this.lastBase||this.lastBase.isLowerEqualPriority(base)){
            if(this.isPending()){
                let index=this.children.findIndex(c=>c.base==base);
                if(index>=0){
                    this.children.splice(index,1);
                    if(this.children.length>0)
                        return;
                }else if(this.children[0].isEqualPriority(base)){
                    return;
                }
            }
            this._accept(base);
        }
    }

    _accept(base){
        this.state=EventState.rejected;
        this.lastBase=base;
    }

    tryPending(base,event){
        if(!event)return;
        if(this.lastBase){
            if(this.lastBase.isLowerEqualPriority(base)){
                this.pushPending(base,event);
                this.lastBase=null;
            }else{
                return;
            }
        }else{
            let last=this.children[0];
            if(!last){
                this.pushPending(base,event);
            }else{
                if(last.base.isEqualPriority(base)){
                    this.pushPending(base,event);
                }else if(last.base.isHigherPriority(base)){
                    this.clearPending();
                    this.pushPending(base,event);
                }else{
                    return;
                }
            }
            
        }
        this.state=EventState.pending;
    }

    tryCancelPending(event){
        if(!this.isPending())return;
        let index=this.children.findIndex(c=>c.event==event);
        if(index>=0){
            let child=this.children[index];
            this.children.splice(index,1);
            if(this.hasNoPending()){
                this._accept(child.base);
            }
            event.parent=null;
        }
    }

    pushPending(base,event){
        event.parent=this;
        this.children.push({base,event});
    }

    clearPending(){
        for(let child of this.children){
            child.event.parent=null;
        }
        this.children.length=0;
    }

    setReason(reason){
        this.reason=reason;
    }

    hasNoPending(){return !this.children.length;}

    //表示悬挂链的末端，此时必须处理悬挂事件
    isPendingEnd(){return this.parent&&!this.children.length;}

    interrupt(){this.state=EventState.interrupted;}
    isAccepted(){return this.state==EventState.accepted;}
    isRejected(){return this.state==EventState.rejected;}
    isInterrupted(){return this.state==EventState.interrupted;}
    isPending(){return this.state==EventState.pending;}
}

